package ltd.hxya.novel.rabbitmq.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import ltd.hxya.novel.common.constant.rabbit.RabbitConstant;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.text.DateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@Configuration
public class RabbitMqConfig {

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        rabbitTemplate.setConnectionFactory(connectionFactory);
        rabbitTemplate.setMessageConverter(messageConverter());
        //设置对消息投递到交换机，但没有投递到队列时的处理
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                log.error("投递的信息：{}，状态码：{}，回复信息：{}，投递的交换机信息：{}，投递的路由键：{}", message,replyCode,replyText,exchange,routingKey);
                //TODO 重新投递
            }
        });

        //添加消息回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack){
                    log.debug("投递成功！！");
                }else {
                    log.error("投递失败，失败原因："+cause);
                }
            }
        });
        return rabbitTemplate;
    }

    //对序列化的功能增强
    @Bean
    public Jackson2JsonMessageConverter messageConverter(){
        ObjectMapper objectMapper = new ObjectMapper();
        JavaTimeModule javaTimeModule = new JavaTimeModule();
       /* javaTimeModule.addSerializer(
                LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss"))
        );*/
        objectMapper.registerModule(javaTimeModule);
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
        return new Jackson2JsonMessageConverter(objectMapper);
    }

    /**
     * 消费者序列化
     * @param connectionFactory
     * @return
     */
  /*  @Bean
    public RabbitListenerContainerFactory<?> containerFactory(ConnectionFactory connectionFactory){
        SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory = new SimpleRabbitListenerContainerFactory();
        simpleRabbitListenerContainerFactory.setConnectionFactory(connectionFactory);
        simpleRabbitListenerContainerFactory.setMessageConverter(new Jackson2JsonMessageConverter());
        return simpleRabbitListenerContainerFactory;
    }*/

    /**
     * 设置多次异常转发到的错误队列
     * @param rabbitTemplate
     * @return
     */
  /*  @Bean
    public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
        return new RepublishMessageRecoverer(rabbitTemplate,RabbitConstant.ERROR_EXCHANGE,RabbitConstant.ERROR_ROUTING_KEY);
    }*/


    /**
     * ===================================================================================================
     * 创建爬取图书的队列
     */
    @Bean
    public Queue crawlBookQueue(){
        return new Queue(RabbitConstant.CRAWL_BOOK_QUEUE,true,false,false);
    }

    @Bean
    public DirectExchange crawlBookExchange(){
        return new DirectExchange(RabbitConstant.CRAWL_BOOK_EXCHANGE,true,false);
    }

    @Bean
    public Binding crawlBookBinding(){
        return BindingBuilder.bind(crawlBookQueue()).to(crawlBookExchange()).with(RabbitConstant.CRAWL_BOOK_ROUTING_KEY);
    }

    /**
     * =============================================================================================================================
     * 添加消息通知队列,交换机，绑定
     */

    @Bean
    public Queue noticeQueue(){
        return new Queue(RabbitConstant.ADMIN_NOTICE_QUEUE,true,false,false);
    }

    @Bean
    public DirectExchange noticeExchange(){
        return new DirectExchange(RabbitConstant.ADMIN_NOTICE_EXCHANGE,true,false);
    }

    @Bean
    public Binding noticeBinding(){
        return BindingBuilder.bind(noticeQueue()).to(noticeExchange()).with(RabbitConstant.ADMIN_NOTICE_ROUTING_KEY);
    }




    /**
     * =============================================
     * @return
     */
    @Bean
    public Queue crawlTaskQueue(){
        //String name, boolean durable, boolean exclusive, boolean autoDelete
        Queue queue = new Queue(RabbitConstant.CRAWL_TASK_QUEUE,true,false,false);
        return queue;
    }

    @Bean
    public DirectExchange crawlTaskExchange(){
        return new DirectExchange(RabbitConstant.CRAWL_TASK_EXCHANGE,true,false);
    }

    @Bean
    public Binding crawlTaskBinding(){
        return BindingBuilder.bind(crawlTaskQueue()).to(crawlTaskExchange()).with(RabbitConstant.CRAWL_TASK_ROUTING_KEY);
    }

    /**
     * ==================================================
     * @return
     */

    @Bean
    public DirectExchange bookExchange(){
        DirectExchange directExchange = new DirectExchange(RabbitConstant.BOOK_EXCHANGE);
        return directExchange;
    }

    @Bean
    public Queue errorQueue(){
        Queue errorQueue = new Queue(RabbitConstant.ERROR_QUEUE);
        return errorQueue;
    }
    @Bean
    public DirectExchange errorExchange(){
        DirectExchange directExchange = new DirectExchange(RabbitConstant.ERROR_EXCHANGE);
        return directExchange;
    }

    @Bean
    public Binding errorBinding(){
        return BindingBuilder.bind(errorQueue()).to(errorExchange()).with(RabbitConstant.ERROR_ROUTING_KEY);
    }

    //删除小说所有章节队列
    @Bean
    public Queue deleteBookQueue(){
        return new Queue(RabbitConstant.DELETE_BOOK_QUEUE);
    }

    @Bean
    public DirectExchange deleteBookExchange(){
        return new DirectExchange(RabbitConstant.DELETE_BOOK_EXCHANGE);
    }

    @Bean
    public Binding deleteBookBing(){
        return BindingBuilder.bind(deleteBookQueue()).to(deleteBookExchange()).with(RabbitConstant.DELETE_BOOK_ROUTING_KEY);
    }

    @Bean
    public Queue addOperLogQueue(){
        return new Queue(RabbitConstant.OPER_LOG_ADD_QUEUE);
    }

    @Bean
    public DirectExchange addOperLogExchange(){
        return new DirectExchange(RabbitConstant.OPER_LOG_ADD_EXCHANGE);
    }

    @Bean
    public Binding addOperLogBinding(){
        return BindingBuilder.bind(addOperLogQueue()).to(addOperLogExchange()).with(RabbitConstant.OPER_LOG_ADD_ROUTING_KEY);
    }

    @Bean
    public Queue addBookContentQueue(){
        return  new Queue(RabbitConstant.BOOKCONTENT_ADD_QUEUE);
    }

    @Bean
    public Binding addBookContentBinding(){
        return BindingBuilder.bind(addBookContentQueue()).to(bookExchange()).with(RabbitConstant.BOOKCONTENT_ADD_ROUTING_KEY);
    }


}
